package summarizer.newversion;

import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;

import thesis.DataUtil;
import thesis.FSModule;
import thesis.InfoUnit;
import thesis.DataObject;
import thesis.Summary;

public class GreedySummarizer extends Summarizer {
	private final double alpha;
	private final double beta;
	private final double gamma;
	private final double[][] probs;
	private final ArrayList<InfoUnit> infoUnits;
	private HashMap<Long, DataObject> memoryTweets;
	private double totalInfo = 1;

	public GreedySummarizer(double[][] probs, ArrayList<InfoUnit> infoUnits,
			double alpha, double beta, double gamma) {
		this.alpha = alpha;
		this.beta = beta;
		this.gamma = gamma;

		this.probs = probs;
		this.infoUnits = infoUnits;
	}

	private void preprocess(Summary summary, int K, int dimSize) {
		// find tweet with best quality
		DataObject bestT = null;
		// initialized totalInfo contained in the dataset
		this.totalInfo = this.getTotalC(memoryTweets, infoUnits, probs);
		double bestScore = -1;
		for (DataObject t : memoryTweets.values()) {
			double coverage = 0;
			for (DataObject otherT : this.memoryTweets.values()) {
				for (InfoUnit unit : this.infoUnits) {
					coverage += probs[otherT.getInternId()][unit.getInternId()]
							* unit.getWeight()
							* (otherT == t ? 1 : probs[t.getInternId()][unit
									.getInternId()]);

				}
			}
			coverage /= this.totalInfo;
			double score = alpha * t.getQuality() / K + gamma * coverage;
			if (score > bestScore) {
				bestScore = score;
				bestT = t;
			}
		}
		summary.addMemoryTweet(bestT);
		this.memoryTweets.remove(bestT.getDbId());
	}

	private void greedProcess(int K, int numberOfPages, Summary summary) {
		List<DataObject> tweetsInS = summary.getMemoryTweets();
		while (tweetsInS.size() < K) {
			double bestScore = -1;
			DataObject bestT = null;
			// compute coverage of each information unit by current summary
			for (InfoUnit info : this.infoUnits) {
				double covProb = 1;
				for (DataObject tInS : tweetsInS) {
					covProb *= (1 - probs[tInS.getInternId()][info
							.getInternId()]);
				}
				info.setCovProb(1 - covProb);
			}
			for (DataObject t : this.memoryTweets.values()) {
				// compute quality for tweet t
				double quality = 0;
				for (DataObject tInS : tweetsInS) {
					quality += tInS.getQuality();
				}
				quality = (quality + t.getQuality()) / K;
				t.setQual(quality);
				// compute diversity after adding t to summary
				double diversity = Double.MAX_VALUE;
				for (int i = 0; i < tweetsInS.size(); i++) {
					double dist = DataUtil.dist(tweetsInS.get(i), t);
					if (dist < diversity) {
						diversity = dist;
					}
					for (int j = i + 1; j < tweetsInS.size(); j++) {
						dist = DataUtil
								.dist(tweetsInS.get(i), tweetsInS.get(j));
						if (dist < diversity) {
							diversity = dist;
						}
					}
				}
				t.setDiv(diversity);
				// compute coverage after adding t to summary
				double coverage = 0;
				for (DataObject tweet : summary.getMemoryTweets()) {
					for (InfoUnit unit : this.infoUnits) {
						coverage += probs[tweet.getInternId()][unit
								.getInternId()] * unit.getWeight();
					}
				}
				for (DataObject tweet : this.memoryTweets.values()) {
					for (InfoUnit unit : this.infoUnits) {
						double newCovProb = 1
								- (1 - unit.getCovProb())
								* (1 - probs[t.getInternId()][unit
										.getInternId()]);
						coverage += probs[tweet.getInternId()][unit
								.getInternId()]
								* unit.getWeight()
								* newCovProb;
					}
				}
				coverage /= this.totalInfo;
				t.setCov(coverage);
				// get summary score
				double summaryScore = alpha * quality + beta * diversity
						+ gamma * coverage;
				if (summaryScore > bestScore) {
					bestScore = summaryScore;
					bestT = t;
				}
			}
			tweetsInS.add(bestT);
			this.memoryTweets.remove(bestT.getDbId());
			// System.out.println("Summary size: " + tweetsInS.size());
			// System.out.println("Quality: " + bestT.getQual() + " Diversity: "
			// + bestT.getDiv() + " Coverage: " + bestT.getCov());
		}
	}

	public Summary computeSummary(int summaryDimension, int numberOfPages,
			HashMap<Long, DataObject> tweets, int dimSize) {
		this.memoryTweets = tweets;
		Summary summary = new Summary();
		if (summaryDimension <= 0 || this.memoryTweets.isEmpty()) {
			return summary;
		}
		System.out.println("Started");
		executionTime = (new GregorianCalendar()).getTimeInMillis();
		preprocess(summary, summaryDimension, dimSize);
		greedProcess(summaryDimension, numberOfPages, summary);
		executionTime = (new GregorianCalendar()).getTimeInMillis()
				- executionTime;
		// compute statistics
		System.out
				.println("finish: use " + executionTime / 1000.0 + "secondes");
		return summary;
	}

	public String toString() {
		return "Greedy Summarizer <" + alpha + " " + beta + " " + gamma + ">";
	}

	public long getExecutionTime() {
		return executionTime;
	}
}
